using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Threading;
using System.Drawing.Imaging;
using System.Globalization;

namespace PaintDotNetForms
{
    public partial class FrmMain : Form
    {
        private bool isMouseDown = false;
        private Color foreColor;
        private Color backColor;        
        private Bitmap buffer;
        private List<Bitmap> snapshots;
        private int cidx = 0;

        private Figure currentShape;

        private bool fromUndoRedo = false;
        private Panel orgPanel;

        public FrmMain()
        {
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(new ConfigManager().Config.Lang);
            InitializeComponent();
            pnlDrawingArea.Size = new Size(800, 600);
            snapshots = new List<Bitmap>();
            snapshots.Add(new Bitmap(pnlDrawingArea.Width, pnlDrawingArea.Height));
            foreColor = Color.Black;            
            orgPanel = new Panel()
            {
                BackColor = pnlDrawingArea.BackColor,
                Width = pnlDrawingArea.Width,
                Height = pnlDrawingArea.Height
            };
            bindBrushWidths();
            bindDashed();
            tsbForeColor.BackColor = foreColor = Color.Black;
            tsbFillColor.BackColor = backColor = Color.AliceBlue;
            currentShape = new Pencil();
            setToolBarButtonStates(tsbPencil);
            tscbxFigureDrawMode.SelectedIndex = 0;
            tscBrashStyle.SelectedIndex = 0;
            setUpCurrentShape();
            bindDashCap();
        }

        private void setUndoRedoButtons()
        {
            tsbPrev.Enabled = true;
            tsbNext.Enabled = true;
            if (cidx == 0)
            {
                tsbPrev.Enabled = false;
                tsbNext.Enabled = true;
            }            
            
            if (cidx == snapshots.Count - 1)
                tsbNext.Enabled = false;
            else
                tsbNext.Enabled = true;
        }

        private void tsbPrev_Click(object sender, EventArgs e)
        {            
            cidx--;
            buffer = snapshots[cidx];
            fromUndoRedo = true;
            pnlDrawingArea.Invalidate();
            pnlDrawingArea.Update();
            setUndoRedoButtons();
        }

        private void tsbNext_Click(object sender, EventArgs e)
        {
            cidx++;
            buffer = snapshots[cidx];
            fromUndoRedo = true;
            pnlDrawingArea.Invalidate();
            pnlDrawingArea.Update();
            setUndoRedoButtons();
        }

        private void setToolBarButtonStates(object buttonToSelect)
        {
            foreach (Component ctrl in tsTools.Items)
            {
                if (ctrl is ToolStripButton)
                {
                    ToolStripButton btn;
                    if ((btn = (ToolStripButton)ctrl) == buttonToSelect)
                    {
                        btn.Checked = true;
                    }
                    else
                        btn.Checked = false;
                }
            }

            if ((buttonToSelect as ToolStripButton) == tsbRectangle ||
                (buttonToSelect as ToolStripButton) == tsbEclipse)
                tscbxFigureDrawMode.Enabled = true;
            else
                tscbxFigureDrawMode.Enabled = false;
        }

        private void tsbPencil_Click(object sender, EventArgs e)
        {
            setToolBarButtonStates(sender);
            currentShape = new Pencil();
            setUpCurrentShape();
        }

        private void tsbRectangle_Click(object sender, EventArgs e)
        {
            setToolBarButtonStates(sender);
            tscbxFigureDrawMode.Enabled = true;
            currentShape = new RectangleShape();
            currentShape.SizeChangeEvent += new SizeChange(currentShape_SizeChangeEvent);
            setUpCurrentShape();
        }

        void currentShape_SizeChangeEvent(Size size)
        {   
            //System.Diagnostics.Debug.WriteLine(String.Concat(size.Width.ToString(), " x ", size.Height.ToString()));
            tsLabelSize.Text = String.Concat("Size: " , size.Width.ToString(), " x ", size.Height.ToString());            
        }

        private void tsbLine_Click(object sender, EventArgs e)
        {
            setToolBarButtonStates(sender);
            currentShape = new LineShape();
            setUpCurrentShape();            
        }

        private void pnlDrawingArea_Paint(object sender, PaintEventArgs e)
        {
            if (fromUndoRedo)
            {
                e.Graphics.DrawImageUnscaled(buffer, 0, 0);
                fromUndoRedo = false;
                return;
            }
            if (buffer != null)
            {
                if(currentShape.GetType() != typeof(Pencil))
                    buffer = snapshots[snapshots.Count - 1].Clone() as Bitmap;

                Graphics g = Graphics.FromImage(buffer);
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                currentShape.draw(g);
                e.Graphics.DrawImageUnscaled(buffer, 0, 0);
                g.Dispose();
            }
        }

        private void pnlDrawingArea_MouseDown(object sender, MouseEventArgs e)
        {
            isMouseDown = true;
            currentShape.setStartPoint(new Point(e.X, e.Y));

            List<Bitmap> tmpSnaps = new List<Bitmap>();
            for (int i = 0; i < cidx + 1; i++)
                tmpSnaps.Add(snapshots[i].Clone() as Bitmap);

            snapshots = tmpSnaps;

            buffer = snapshots[snapshots.Count - 1].Clone() as Bitmap;
        }

        private void pnlDrawingArea_MouseMove(object sender, MouseEventArgs e)
        {
            if (isMouseDown)
            {
                currentShape.setEndPoint(new Point(e.X, e.Y));
                pnlDrawingArea.Invalidate();
                pnlDrawingArea.Update();
            }
            else
            {
                currentShape.setStartPoint(new Point(0, 0));
                currentShape.setEndPoint(new Point(0, 0));
            }
        }

        private void pnlDrawingArea_MouseUp(object sender, MouseEventArgs e)
        {
            isMouseDown = false;
            snapshots.Add(buffer.Clone() as Bitmap);
            cidx++;
            setUndoRedoButtons();
        }

        private void pnlContrainer_Paint(object sender, PaintEventArgs e)
        {
            /*e.Graphics.DrawRectangle(Pens.Black,
                pnlDrawingArea.Width,
                pnlDrawingArea.Height,
                10, 10);*/
        }

        private void pnlContrainer_MouseMove(object sender, MouseEventArgs e)
        {
            Cursor = Cursors.Default;
            //if (e.X > pnlDrawingArea.Width && e.X < pnlDrawingArea.Width + 10)
            //    Cursor = Cursors.SizeNWSE;
        }

        private void newPainting()
        {            
            FrmNewSize fns;
            if ((fns = new FrmNewSize() { PnlSize = pnlDrawingArea.Size  }).ShowDialog() == DialogResult.OK)
            {
                snapshots.Clear();
                cidx = 0;
                snapshots.Add(new Bitmap(fns.PnlSize.Width, fns.PnlSize.Height));
                pnlDrawingArea.Size = fns.PnlSize;
                buffer = snapshots[0] as Bitmap;
                pnlDrawingArea.Invalidate();
                pnlDrawingArea.Update();
            }
        }

        private void tsbNew_Click(object sender, EventArgs e)
        {
            newPainting();
            setUndoRedoButtons();
        }

        private void bindBrushWidths()
        {
            for(int i = 0 ; i < 10 ; i++)
                tscbxBrushes.Items.Add((i + 1).ToString());
            tscbxBrushes.SelectedIndex = 0;
        }

        private void bindDashed()
        {
            string[] dashes = Enum.GetNames(typeof(DashStyle));
            for (int i = 0 ; i < dashes.Length - 1 ; i++)
                tscBrashStyle.Items.Add(dashes[i]);            
        }

        private void bindDashCap()
        {
            string[] dashCaps = Enum.GetNames(typeof(DashCap));
            for (int i = 0; i < dashCaps.Length; i++)
            {
                var mi = new MenuItem(dashCaps[i]);
                tsbDashCap.DropDownItems.Add(new ToolStripMenuItem(dashCaps[i]));
                tsbDashCap.DropDownItems[i].Click += delegate(object sender, EventArgs e)
                {
                    for (int it = 0; it < tsbDashCap.DropDownItems.Count; it++)
                    {
                        (tsbDashCap.DropDownItems[it] as ToolStripMenuItem).Checked = false;
                        if(tsbDashCap.DropDownItems[it] == sender)
                            (tsbDashCap.DropDownItems[it] as ToolStripMenuItem).Checked = true;
                    }
                    setUpCurrentShape();
                };
            }
            (tsbDashCap.DropDownItems[0] as ToolStripMenuItem).Checked = true;
        }

        private void tsbBrushWidthPlus_Click(object sender, EventArgs e)
        {
            if (tscbxBrushes.SelectedIndex + 1 < tscbxBrushes.Items.Count)
                ++tscbxBrushes.SelectedIndex;
        }

        private void tsbBrushWidthMinus_Click(object sender, EventArgs e)
        {
            if (tscbxBrushes.SelectedIndex - 1 > -1)
                --tscbxBrushes.SelectedIndex;
        }

        private void tsComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (tscbxBrushes.SelectedIndex == 0)
                tsbBrushWidthMinus.Enabled = false;
            else
                tsbBrushWidthMinus.Enabled = true;

            if (tscbxBrushes.SelectedIndex == tscbxBrushes.Items.Count - 1)
                tsbBrushWidthPlus.Enabled = false;
            else
                tsbBrushWidthPlus.Enabled = true;

            setUpCurrentShape();
        }

        private void tsbForeColor_Click(object sender, EventArgs e)
        {
            colorDialog.Color = foreColor;
            if (colorDialog.ShowDialog() == DialogResult.OK)
            {                
                tsbForeColor.BackColor = foreColor = colorDialog.Color;
                setUpCurrentShape();
            }
        }

        private void setUpCurrentShape()
        {
            if (currentShape == null)
                return;
            
            currentShape.Filling = (Filling)Enum.Parse(typeof(Filling), 
                tscbxFigureDrawMode.Items[tscbxFigureDrawMode.SelectedIndex].ToString().Replace(" ",""), true);
            
            currentShape.setPen(new Pen(foreColor, int.Parse(tscbxBrushes.SelectedItem.ToString())));
            currentShape.setDashStyle((DashStyle)Enum.Parse(typeof(DashStyle), 
                tscBrashStyle.Items[tscBrashStyle.SelectedIndex != -1 ? tscBrashStyle.SelectedIndex : 0].ToString()));            
            currentShape.setBrush(new SolidBrush(backColor));
            for (int i = 0 ; i < tsbDashCap.DropDownItems.Count; i++)
            {
                if ((tsbDashCap.DropDownItems[i] as ToolStripMenuItem).Checked)
                    currentShape.setDashCap((DashCap)Enum.Parse(typeof(DashCap), (tsbDashCap.DropDownItems[i] as ToolStripMenuItem).Text));
            }
        }

        private void tsbEclipse_Click(object sender, EventArgs e)
        {
            currentShape = new Eclipse();            
            setToolBarButtonStates(sender);
            setUpCurrentShape();
        }

        private void FrmMain_KeyDown(object sender, KeyEventArgs e)
        {
            if(e.Shift)
                currentShape.ShiftIsDown = true;
        }

        private void FrmMain_KeyUp(object sender, KeyEventArgs e)
        {
            currentShape.ShiftIsDown = false;
        }

        private void tsbFillColor_Click(object sender, EventArgs e)
        {
            colorDialog.Color = backColor;
            if (colorDialog.ShowDialog() == DialogResult.OK)
            {                
                tsbFillColor.BackColor = backColor = colorDialog.Color;
                setUpCurrentShape();
            }
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd;
            if ((sfd = new SaveFileDialog() { Filter = "Bitmapa (*.bmp)|*.bmp|Wszystkie pliki (*.*)|*.*" }).ShowDialog() == DialogResult.OK)
                snapshots[snapshots.Count - 1].Save(sfd.FileName);
        }

        private void tscbxFigureDrawMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            setUpCurrentShape();
        }

        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            newPainting();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show(this, "Paint .NET Forms\nAutor: Łukasz Kasprzyk nr. indeksu: 61236\nPP Inf. TWO SUM", "About.", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void jezykToolStripMenuItem_Click(object sender, EventArgs e)
        {            
            FrmLang frmLang = null;
            if ((frmLang = new FrmLang()).ShowDialog() == DialogResult.OK)
            {
                string message = "Language will be changed next time you run application.\nWould you like to now resart now?";

                switch (MessageBox.Show(this, message, "Language changing.", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
                {
                    case DialogResult.Yes:
                        new ConfigManager().Save(new Config() { Lang = frmLang.SelectedLangCode });
                        Application.Restart();
                        break;
                    case DialogResult.No:
                        new ConfigManager().Save(new Config() { Lang = frmLang.SelectedLangCode });
                        break;
                    case DialogResult.Cancel:
                        break;
                }
            }
        }

        private void tscBrushStyle_SelectedIndexChanged(object sender, EventArgs e)
        {
            setUpCurrentShape();
        }

        private void tsbDashCap_ButtonClick(object sender, EventArgs e)
        {
            tsbDashCap.ShowDropDown();
        }
    }
}